class OnEmitRemoveMan {
    constructor(){
        this.planObj = {};
    }
    on(cmd, fn){
        if(this.planObj[cmd] == undefined) this.planObj[cmd] = [];
        this.planObj[cmd].push(fn);
    }
    emit(cmd){
        const arg = [...arguments].slice(1);
        this.planObj[cmd].forEach((item, index) => {
            item(...arg);
            // console.log(this)
        })
    }
    remove(cmd, fn){
        if(this.planObj[cmd] == undefined) throw `${cmd} event has not bind to this.planObj`;
        if(this.planObj[cmd].every((item)=>item!==fn)) console.log(`${cmd} event stack has no special function.`);
        this.planObj[cmd] = this.planObj[cmd].filter(function (item, index) {
            return item !== fn;
        })
    }
    removeFirst(cmd, fn){
        if(this.planObj[cmd] == undefined) throw `${cmd} event has not bind to this.planObj`;
        if(this.planObj[cmd].every((item)=>item!==fn)) console.log(`${cmd} event stack has no special function.`);
        const rmIndex = this.planObj[cmd].findIndex(function (item) {
            return item === fn;
        });
        this.planObj[cmd].splice(rmIndex, 1);
    }
}

//以下为简单测试
console.log(`\n测试传入不接收参数的回调函数:`);
const oe1 = new OnEmitRemoveMan();
oe1.on('say hello', ()=> {console.log('hello1')});
oe1.on('say hello', ()=> {console.log('hello2')});
oe1.emit('say hello');

console.log(`\n测试传入要接收参数的回调函数:`);
const say = (yourWords)=>{
    return ()=>{
        console.log(yourWords);
    }
};
oe1.on('say your words', ()=>{
    console.log('how old are you?')
});
oe1.on('say your words', ((wds)=>{
    return say(wds)
})('what is your name?'));
oe1.on('say your words', ((wds)=>{
    return say(wds)
})('how are your?'));
oe1.emit('say your words');

console.log(`\n测试remove方法:`);
const fnAry = [...new Array(5).keys()].reduce((fAry, num)=>{
       fAry.push(new Function(`console.log(${num})`))
       return fAry;
   }, []);
fnAry.forEach((fn)=>{
    oe1.on('for remove test', fn);
});
oe1.emit('for remove test');
oe1.remove('for remove test', fnAry[2])
console.log(`removed the function which will output number 2.`);
oe1.emit('for remove test');

console.log(`\n测试removeFirst方法:`);
const bindForRemoveFirst = () => fnAry.forEach((fn)=>{
    oe1.on('for removeFirst test', fn);
});
bindForRemoveFirst();
bindForRemoveFirst();
oe1.emit('for removeFirst test');
oe1.removeFirst('for removeFirst test', fnAry[2])
console.log(`removed the first function which will output number 2.`);
oe1.emit('for removeFirst test');
